ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ಭಾಗಶಃ ಟೈಪ್ ತೀರ್ಮಾನದ ಬಗ್ಗೆ ಆಳವಾದ ವಿಶ್ಲೇಷಣೆ. ಟೈಪ್ ರೆಸಲ್ಯೂಶನ್ ಅಪೂರ್ಣವಾಗಿರುವ ಸನ್ನಿವೇಶಗಳನ್ನು ಪರಿಶೋಧಿಸುವುದು ಮತ್ತು ಅವುಗಳನ್ನು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ನಿಭಾಯಿಸುವುದು ಹೇಗೆಂದು ತಿಳಿಯಿರಿ.
ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಭಾಗಶಃ ತೀರ್ಮಾನ: ಅಪೂರ್ಣ ಟೈಪ್ ರೆಸಲ್ಯೂಶನ್ ಅನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು
ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ಟೈಪ್ ಸಿಸ್ಟಮ್ ದೃಢವಾದ ಮತ್ತು ನಿರ್ವಹಿಸಬಲ್ಲ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿರ್ಮಿಸಲು ಒಂದು ಶಕ್ತಿಯುತ ಸಾಧನವಾಗಿದೆ. ಇದರ ಪ್ರಮುಖ ವೈಶಿಷ್ಟ್ಯವೆಂದರೆ ಟೈಪ್ ತೀರ್ಮಾನ (type inference), ಇದು ಕಂಪೈಲರ್ಗೆ ವೇರಿಯಬಲ್ಗಳು ಮತ್ತು ಎಕ್ಸ್ಪ್ರೆಶನ್ಗಳ ಟೈಪ್ಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನಿರ್ಧರಿಸಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ, ಇದರಿಂದ ಸ್ಪಷ್ಟವಾದ ಟೈಪ್ ವಿವರಣೆಗಳ ಅಗತ್ಯವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ. ಆದಾಗ್ಯೂ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ಟೈಪ್ ತೀರ್ಮಾನ ಯಾವಾಗಲೂ ಪರಿಪೂರ್ಣವಾಗಿರುವುದಿಲ್ಲ. ಇದು ಕೆಲವೊಮ್ಮೆ "ಭಾಗಶಃ ತೀರ್ಮಾನ" (partial inference) ಎಂದು ಕರೆಯಲ್ಪಡುವ ಸ್ಥಿತಿಗೆ ಕಾರಣವಾಗಬಹುದು, ಅಲ್ಲಿ ಕೆಲವು ಟೈಪ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳನ್ನು ತೀರ್ಮಾನಿಸಲಾಗುತ್ತದೆ ಆದರೆ ಇತರವುಗಳು ಅಜ್ಞಾತವಾಗಿ ಉಳಿಯುತ್ತವೆ, ಇದು ಅಪೂರ್ಣ ಟೈಪ್ ರೆಸಲ್ಯೂಶನ್ಗೆ ಕಾರಣವಾಗುತ್ತದೆ. ಇದು ವಿವಿಧ ರೀತಿಗಳಲ್ಲಿ ಪ್ರಕಟವಾಗಬಹುದು ಮತ್ತು ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ತೀರ್ಮಾನ ಅಲ್ಗಾರಿದಮ್ ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದರ ಬಗ್ಗೆ ಆಳವಾದ ತಿಳುವಳಿಕೆ ಅಗತ್ಯವಿರುತ್ತದೆ.
ಭಾಗಶಃ ಟೈಪ್ ತೀರ್ಮಾನ ಎಂದರೇನು?
ಜೆನೆರಿಕ್ ಫಂಕ್ಷನ್ ಅಥವಾ ಟೈಪ್ಗಾಗಿ ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಕೆಲವು, ಆದರೆ ಎಲ್ಲಾ ಟೈಪ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳನ್ನು ತೀರ್ಮಾನಿಸಲು ಸಾಧ್ಯವಾದಾಗ ಭಾಗಶಃ ಟೈಪ್ ತೀರ್ಮಾನ ಸಂಭವಿಸುತ್ತದೆ. ಸಂಕೀರ್ಣ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳು, ಷರತ್ತುಬದ್ಧ ಟೈಪ್ಗಳೊಂದಿಗೆ ವ್ಯವಹರಿಸುವಾಗ ಅಥವಾ ಕಂಪೈಲರ್ಗೆ ತಕ್ಷಣವೇ ಟೈಪ್ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲದಿದ್ದಾಗ ಇದು ಹೆಚ್ಚಾಗಿ ಸಂಭವಿಸುತ್ತದೆ. ತೀರ್ಮಾನಿಸದ ಟೈಪ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳನ್ನು ಸಾಮಾನ್ಯವಾಗಿ `any` ಟೈಪ್ನಂತೆ ಬಿಡಲಾಗುತ್ತದೆ, ಅಥವಾ ಡಿಫಾಲ್ಟ್ ಟೈಪ್ ಪ್ಯಾರಾಮೀಟರ್ ಮೂಲಕ ನಿರ್ದಿಷ್ಟಪಡಿಸಿದಲ್ಲಿ ಹೆಚ್ಚು ನಿರ್ದಿಷ್ಟವಾದ ಫಾಲ್ಬ್ಯಾಕ್ ಆಗಿರುತ್ತದೆ.
ಇದನ್ನು ಒಂದು ಸರಳ ಉದಾಹರಣೆಯೊಂದಿಗೆ ವಿವರಿಸೋಣ:
function createPair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const pair1 = createPair(1, "hello"); // Inferred as [number, string]
const pair2 = createPair<number>(1, "hello"); // U is inferred as string, T is explicitly number
const pair3 = createPair(1, {}); //Inferred as [number, {}]
ಮೊದಲ ಉದಾಹರಣೆಯಲ್ಲಿ, `createPair(1, "hello")`, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ `T` ಅನ್ನು `number` ಮತ್ತು `U` ಅನ್ನು `string` ಎಂದು ತೀರ್ಮಾನಿಸುತ್ತದೆ ಏಕೆಂದರೆ ಫಂಕ್ಷನ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳಿಂದ ಅದಕ್ಕೆ ಸಾಕಷ್ಟು ಮಾಹಿತಿ ಲಭ್ಯವಿದೆ. ಎರಡನೇ ಉದಾಹರಣೆಯಲ್ಲಿ, `createPair<number>(1, "hello")`, ನಾವು `T` ಗಾಗಿ ಟೈಪ್ ಅನ್ನು ಸ್ಪಷ್ಟವಾಗಿ ಒದಗಿಸುತ್ತೇವೆ, ಮತ್ತು ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಎರಡನೇ ಆರ್ಗ್ಯುಮೆಂಟ್ ಆಧಾರದ ಮೇಲೆ `U` ಅನ್ನು ತೀರ್ಮಾನಿಸುತ್ತದೆ. ಮೂರನೇ ಉದಾಹರಣೆಯು ಸ್ಪಷ್ಟ ಟೈಪಿಂಗ್ ಇಲ್ಲದ ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ಗಳನ್ನು `{}` ಎಂದು ಹೇಗೆ ತೀರ್ಮಾನಿಸಲಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ತೋರಿಸುತ್ತದೆ.
ಕಂಪೈಲರ್ಗೆ ಎಲ್ಲಾ ಅಗತ್ಯ ಟೈಪ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳನ್ನು ನಿರ್ಧರಿಸಲು ಸಾಧ್ಯವಾಗದಿದ್ದಾಗ ಭಾಗಶಃ ತೀರ್ಮಾನವು ಹೆಚ್ಚು ಸಮಸ್ಯಾತ್ಮಕವಾಗುತ್ತದೆ, ಇದು ಸಂಭಾವ್ಯ ಅಸುರಕ್ಷಿತ ಅಥವಾ ಅನಿರೀಕ್ಷಿತ ನಡವಳಿಕೆಗೆ ಕಾರಣವಾಗಬಹುದು. ಹೆಚ್ಚು ಸಂಕೀರ್ಣವಾದ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳು ಮತ್ತು ಷರತ್ತುಬದ್ಧ ಟೈಪ್ಗಳೊಂದಿಗೆ ವ್ಯವಹರಿಸುವಾಗ ಇದು ವಿಶೇಷವಾಗಿ ಸತ್ಯ.
ಭಾಗಶಃ ತೀರ್ಮಾನ ಸಂಭವಿಸುವ ಸನ್ನಿವೇಶಗಳು
ನೀವು ಭಾಗಶಃ ಟೈಪ್ ತೀರ್ಮಾನವನ್ನು ಎದುರಿಸಬಹುದಾದ ಕೆಲವು ಸಾಮಾನ್ಯ ಸಂದರ್ಭಗಳು ಇಲ್ಲಿವೆ:
1. ಸಂಕೀರ್ಣ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳು
ಆಳವಾಗಿ ನೆಸ್ಟೆಡ್ ಅಥವಾ ಸಂಕೀರ್ಣ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವಾಗ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಎಲ್ಲಾ ಟೈಪ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳನ್ನು ಸರಿಯಾಗಿ ತೀರ್ಮಾನಿಸಲು ಕಷ್ಟಪಡಬಹುದು. ಟೈಪ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳ ನಡುವೆ ಅವಲಂಬನೆಗಳಿದ್ದಾಗ ಇದು ವಿಶೇಷವಾಗಿ ಸತ್ಯ.
interface Result<T, E> {
success: boolean;
data?: T;
error?: E;
}
function processResult<T, E>(result: Result<T, E>): T | E {
if (result.success) {
return result.data!;
} else {
return result.error!;
}
}
const successResult: Result<string, Error> = { success: true, data: "Data" };
const errorResult: Result<string, Error> = { success: false, error: new Error("Something went wrong") };
const data = processResult(successResult); // Inferred as string | Error
const error = processResult(errorResult); // Inferred as string | Error
ಈ ಉದಾಹರಣೆಯಲ್ಲಿ, `processResult` ಫಂಕ್ಷನ್ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳಾದ `T` ಮತ್ತು `E` ಜೊತೆಗೆ `Result` ಟೈಪ್ ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ. ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ `successResult` ಮತ್ತು `errorResult` ವೇರಿಯಬಲ್ಗಳ ಆಧಾರದ ಮೇಲೆ ಈ ಟೈಪ್ಗಳನ್ನು ತೀರ್ಮಾನಿಸುತ್ತದೆ. ಆದಾಗ್ಯೂ, ನೀವು ನೇರವಾಗಿ ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ನೊಂದಿಗೆ `processResult` ಅನ್ನು ಕರೆದರೆ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಟೈಪ್ಗಳನ್ನು ಅಷ್ಟು ನಿಖರವಾಗಿ ತೀರ್ಮಾನಿಸಲು ಸಾಧ್ಯವಾಗದಿರಬಹುದು. ಆರ್ಗ್ಯುಮೆಂಟ್ ಆಧಾರದ ಮೇಲೆ ರಿಟರ್ನ್ ಟೈಪ್ ಅನ್ನು ನಿರ್ಧರಿಸಲು ಜೆನೆರಿಕ್ಸ್ ಬಳಸುವ ವಿಭಿನ್ನ ಫಂಕ್ಷನ್ ಡೆಫಿನಿಷನ್ ಅನ್ನು ಪರಿಗಣಿಸಿ.
function extractValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const myObject = { name: "Alice", age: 30 };
const nameValue = extractValue(myObject, "name"); // Inferred as string
const ageValue = extractValue(myObject, "age"); // Inferred as number
//Example showing potential partial inference with a dynamically constructed type
type DynamicObject = { [key: string]: any };
function processDynamic<T extends DynamicObject, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const dynamicObj:DynamicObject = {a: 1, b: "hello"};
const result = processDynamic(dynamicObj, "a"); //result is inferred as any, because DynamicObject defaults to any
ಇಲ್ಲಿ, ನಾವು `DynamicObject` ಗಿಂತ ಹೆಚ್ಚು ನಿರ್ದಿಷ್ಟವಾದ ಟೈಪ್ ಅನ್ನು ಒದಗಿಸದಿದ್ದರೆ, ತೀರ್ಮಾನವು `any` ಗೆ ಡಿಫಾಲ್ಟ್ ಆಗುತ್ತದೆ.
2. ಷರತ್ತುಬದ್ಧ ಟೈಪ್ಗಳು
ಷರತ್ತುಬದ್ಧ ಟೈಪ್ಗಳು ಒಂದು ಷರತ್ತನ್ನು ಅವಲಂಬಿಸಿರುವ ಟೈಪ್ಗಳನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಲು ನಿಮಗೆ ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ. ಇವು ಶಕ್ತಿಯುತವಾಗಿದ್ದರೂ, ಅವು ತೀರ್ಮಾನದ ಸವಾಲುಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು, ವಿಶೇಷವಾಗಿ ಷರತ್ತು ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳನ್ನು ಒಳಗೊಂಡಿರುವಾಗ.
type IsString<T> = T extends string ? true : false;
function processValue<T>(value: T): IsString<T> {
// This function doesn't actually do anything useful at runtime,
// it's just for illustrating type inference.
return (typeof value === 'string') as IsString<T>;
}
const stringValue = processValue("hello"); // Inferred as IsString<string> (which resolves to true)
const numberValue = processValue(123); // Inferred as IsString<number> (which resolves to false)
//Example where the function definition does not allow inference
function processValueNoInfer<T>(value: T): T extends string ? true : false {
return (typeof value === 'string') as T extends string ? true : false;
}
const stringValueNoInfer = processValueNoInfer("hello"); // Inferred as boolean, because the return type is not a dependent type
ಮೊದಲ ಉದಾಹರಣೆಗಳ ಸೆಟ್ನಲ್ಲಿ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಜೆನೆರಿಕ್ `IsString
3. ಡಿಫಾಲ್ಟ್ ಟೈಪ್ ಪ್ಯಾರಾಮೀಟರ್ಗಳು ಮತ್ತು `any`
ಒಂದು ಜೆನೆರಿಕ್ ಟೈಪ್ ಪ್ಯಾರಾಮೀಟರ್ ಡಿಫಾಲ್ಟ್ ಟೈಪ್ ಹೊಂದಿದ್ದರೆ (ಉದಾಹರಣೆಗೆ, `
function logValue<T = any>(value: T): void {
console.log(value);
}
logValue(123); // T is any, so no type checking
logValue("hello"); // T is any
logValue({ a: 1 }); // T is any
function logValueTyped<T = string>(value: T): void {
console.log(value);
}
logValueTyped(123); // Error: Argument of type 'number' is not assignable to parameter of type 'string | undefined'.
ಮೊದಲ ಉದಾಹರಣೆಯಲ್ಲಿ, ಡಿಫಾಲ್ಟ್ ಟೈಪ್ ಪ್ಯಾರಾಮೀಟರ್ `T = any` ಎಂದರೆ ಯಾವುದೇ ಟೈಪ್ ಅನ್ನು ಕಂಪೈಲರ್ನಿಂದ ಯಾವುದೇ ದೂರು ಇಲ್ಲದೆ `logValue` ಗೆ ಪಾಸ್ ಮಾಡಬಹುದು. ಇದು ಸಂಭಾವ್ಯವಾಗಿ ಅಪಾಯಕಾರಿ, ಏಕೆಂದರೆ ಇದು ಟೈಪ್ ಚೆಕಿಂಗ್ ಅನ್ನು ಬೈಪಾಸ್ ಮಾಡುತ್ತದೆ. ಎರಡನೇ ಉದಾಹರಣೆಯಲ್ಲಿ, `T = string` ಉತ್ತಮ ಡಿಫಾಲ್ಟ್ ಆಗಿದೆ, ಏಕೆಂದರೆ ನೀವು `logValueTyped` ಗೆ ಸ್ಟ್ರಿಂಗ್ ಅಲ್ಲದ ಮೌಲ್ಯವನ್ನು ಪಾಸ್ ಮಾಡಿದಾಗ ಅದು ಟೈಪ್ ದೋಷಗಳನ್ನು ಪ್ರಚೋದಿಸುತ್ತದೆ.
4. ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ಗಳಿಂದ ತೀರ್ಮಾನ
ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ಗಳಿಂದ ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ತೀರ್ಮಾನವು ಕೆಲವೊಮ್ಮೆ ಆಶ್ಚರ್ಯಕರವಾಗಿರುತ್ತದೆ. ನೀವು ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ ಅನ್ನು ನೇರವಾಗಿ ಫಂಕ್ಷನ್ಗೆ ಪಾಸ್ ಮಾಡಿದಾಗ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ನೀವು ನಿರೀಕ್ಷಿಸಿದ್ದಕ್ಕಿಂತ ಸಂಕುಚಿತ ಟೈಪ್ ಅನ್ನು ತೀರ್ಮಾನಿಸಬಹುದು, ಅಥವಾ ಅದು ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳನ್ನು ಸರಿಯಾಗಿ ತೀರ್ಮಾನಿಸದಿರಬಹುದು. ಏಕೆಂದರೆ ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ಗಳಿಂದ ಟೈಪ್ಗಳನ್ನು ತೀರ್ಮಾನಿಸುವಾಗ ಸಾಧ್ಯವಾದಷ್ಟು ನಿರ್ದಿಷ್ಟವಾಗಿರಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ, ಆದರೆ ಇದು ಜೆನೆರಿಕ್ಸ್ನೊಂದಿಗೆ ವ್ಯವಹರಿಸುವಾಗ ಕೆಲವೊಮ್ಮೆ ಅಪೂರ್ಣ ತೀರ್ಮಾನಕ್ಕೆ ಕಾರಣವಾಗಬಹುದು.
interface Options<T> {
value: T;
label: string;
}
function processOptions<T>(options: Options<T>): void {
console.log(options.value, options.label);
}
processOptions({ value: 123, label: "Number" }); // T is inferred as number
//Example where type is not correctly inferred when the properties are not defined at initialization
function createOptions<T>(): Options<T>{
return {value: undefined as any, label: ""}; //incorrectly infers T as never because it is initialized with undefined
}
let options = createOptions<number>(); //Options, BUT value can only be set as undefined without error
ಮೊದಲ ಉದಾಹರಣೆಯಲ್ಲಿ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ನ `value` ಪ್ರಾಪರ್ಟಿ ಆಧಾರದ ಮೇಲೆ `T` ಅನ್ನು `number` ಎಂದು ತೀರ್ಮಾನಿಸುತ್ತದೆ. ಆದಾಗ್ಯೂ, ಎರಡನೇ ಉದಾಹರಣೆಯಲ್ಲಿ, `createOptions` ನ `value` ಪ್ರಾಪರ್ಟಿಯನ್ನು ಇನಿಶಿಯಲೈಸ್ ಮಾಡುವುದರಿಂದ, ಕಂಪೈಲರ್ `never` ಎಂದು ತೀರ್ಮಾನಿಸುತ್ತದೆ ಏಕೆಂದರೆ ಜೆನೆರಿಕ್ ಅನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸದೆ `undefined` ಅನ್ನು `never` ಗೆ ಮಾತ್ರ ನಿಯೋಜಿಸಬಹುದು. ಆ ಕಾರಣದಿಂದ, `createOptions` ಗೆ ಯಾವುದೇ ಕರೆಯನ್ನು ನೀವು ಸ್ಪಷ್ಟವಾಗಿ ಪಾಸ್ ಮಾಡಿದರೂ ಸಹ ಜೆನೆರಿಕ್ `never` ಎಂದು ತೀರ್ಮಾನಿಸಲಾಗುತ್ತದೆ. ತಪ್ಪಾದ ಟೈಪ್ ತೀರ್ಮಾನವನ್ನು ತಡೆಯಲು ಈ ಸಂದರ್ಭದಲ್ಲಿ ಯಾವಾಗಲೂ ಡಿಫಾಲ್ಟ್ ಜೆನೆರಿಕ್ ಮೌಲ್ಯಗಳನ್ನು ಸ್ಪಷ್ಟವಾಗಿ ಸೆಟ್ ಮಾಡಿ.
5. ಕಾಲ್ಬ್ಯಾಕ್ ಫಂಕ್ಷನ್ಗಳು ಮತ್ತು ಸಂದರ್ಭೋಚಿತ ಟೈಪಿಂಗ್
ಕಾಲ್ಬ್ಯಾಕ್ ಫಂಕ್ಷನ್ಗಳನ್ನು ಬಳಸುವಾಗ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಕಾಲ್ಬ್ಯಾಕ್ನ ಪ್ಯಾರಾಮೀಟರ್ಗಳು ಮತ್ತು ರಿಟರ್ನ್ ಮೌಲ್ಯದ ಟೈಪ್ಗಳನ್ನು ತೀರ್ಮಾನಿಸಲು ಸಂದರ್ಭೋಚಿತ ಟೈಪಿಂಗ್ (contextual typing) ಅನ್ನು ಅವಲಂಬಿಸಿದೆ. ಸಂದರ್ಭೋಚಿತ ಟೈಪಿಂಗ್ ಎಂದರೆ ಕಾಲ್ಬ್ಯಾಕ್ನ ಟೈಪ್ ಅನ್ನು ಅದು ಬಳಸಲಾಗುವ ಸಂದರ್ಭದಿಂದ ನಿರ್ಧರಿಸಲಾಗುತ್ತದೆ. ಸಂದರ್ಭವು ಸಾಕಷ್ಟು ಮಾಹಿತಿಯನ್ನು ಒದಗಿಸದಿದ್ದರೆ, ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ಗೆ ಟೈಪ್ಗಳನ್ನು ಸರಿಯಾಗಿ ತೀರ್ಮಾನಿಸಲು ಸಾಧ್ಯವಾಗದಿರಬಹುದು, ಇದು `any` ಅಥವಾ ಇತರ ಅನಪೇಕ್ಷಿತ ಫಲಿತಾಂಶಗಳಿಗೆ ಕಾರಣವಾಗುತ್ತದೆ. ನಿಮ್ಮ ಕಾಲ್ಬ್ಯಾಕ್ ಫಂಕ್ಷನ್ ಸಿಗ್ನೇಚರ್ಗಳನ್ನು ಸರಿಯಾಗಿ ಟೈಪ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಎಚ್ಚರಿಕೆಯಿಂದ ಪರಿಶೀಲಿಸಿ.
function mapArray<T, U>(arr: T[], callback: (item: T, index: number) => U): U[] {
const result: U[] = [];
for (let i = 0; i < arr.length; i++) {
result.push(callback(arr[i], i));
}
return result;
}
const numbers = [1, 2, 3];
const strings = mapArray(numbers, (num, index) => `Number ${num} at index ${index}`); // T is number, U is string
//Example with incomplete context
function processItem<T>(item: T, callback: (item: T) => void) {
callback(item);
}
processItem(1, (item) => {
//item is inferred as any if T cannot be inferred outside the scope of the callback
console.log(item.toFixed(2)); //No type safety.
});
processItem<number>(1, (item) => {
//By explicitly setting the generic parameter, we guarantee that it is a number
console.log(item.toFixed(2)); //Type safety
});
ಮೊದಲ ಉದಾಹರಣೆಯು ಐಟಂ ಅನ್ನು `number` ಮತ್ತು ರಿಟರ್ನ್ ಮಾಡಿದ ಟೈಪ್ ಅನ್ನು `string` ಎಂದು ಸರಿಯಾಗಿ ತೀರ್ಮಾನಿಸಲು ಸಂದರ್ಭೋಚಿತ ಟೈಪಿಂಗ್ ಅನ್ನು ಬಳಸುತ್ತದೆ. ಎರಡನೇ ಉದಾಹರಣೆಯು ಅಪೂರ್ಣ ಸಂದರ್ಭವನ್ನು ಹೊಂದಿದೆ, ಆದ್ದರಿಂದ ಅದು `any` ಗೆ ಡಿಫಾಲ್ಟ್ ಆಗುತ್ತದೆ.
ಅಪೂರ್ಣ ಟೈಪ್ ರೆಸಲ್ಯೂಶನ್ ಅನ್ನು ಹೇಗೆ ನಿಭಾಯಿಸುವುದು
ಭಾಗಶಃ ತೀರ್ಮಾನವು ನಿರಾಶಾದಾಯಕವಾಗಿದ್ದರೂ, ಅದನ್ನು ನಿಭಾಯಿಸಲು ಮತ್ತು ನಿಮ್ಮ ಕೋಡ್ ಟೈಪ್-ಸೇಫ್ ಆಗಿದೆಯೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ನೀವು ಹಲವಾರು ತಂತ್ರಗಳನ್ನು ಬಳಸಬಹುದು:
1. ಸ್ಪಷ್ಟ ಟೈಪ್ ವಿವರಣೆಗಳು (Explicit Type Annotations)
ಅಪೂರ್ಣ ತೀರ್ಮಾನವನ್ನು ನಿಭಾಯಿಸಲು ಅತ್ಯಂತ ನೇರವಾದ ಮಾರ್ಗವೆಂದರೆ ಸ್ಪಷ್ಟ ಟೈಪ್ ವಿವರಣೆಗಳನ್ನು ಒದಗಿಸುವುದು. ಇದು ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ಗೆ ನೀವು ನಿರೀಕ್ಷಿಸುವ ಟೈಪ್ಗಳು ಯಾವುವು ಎಂದು ನಿಖರವಾಗಿ ಹೇಳುತ್ತದೆ, ತೀರ್ಮಾನ ಯಾಂತ್ರಿಕತೆಯನ್ನು ಅತಿಕ್ರಮಿಸುತ್ತದೆ. ಕಂಪೈಲರ್ ಹೆಚ್ಚು ನಿರ್ದಿಷ್ಟವಾದ ಟೈಪ್ ಅಗತ್ಯವಿದ್ದಾಗ `any` ಎಂದು ತೀರ್ಮಾನಿಸಿದಾಗ ಇದು ವಿಶೇಷವಾಗಿ ಉಪಯುಕ್ತವಾಗಿದೆ.
const pair: [number, string] = createPair(1, "hello"); //Explicit type annotation
2. ಸ್ಪಷ್ಟ ಟೈಪ್ ಆರ್ಗ್ಯುಮೆಂಟ್ಗಳು (Explicit Type Arguments)
ಜೆನೆರಿಕ್ ಫಂಕ್ಷನ್ಗಳನ್ನು ಕರೆಯುವಾಗ, ನೀವು ಆಂಗಲ್ ಬ್ರಾಕೆಟ್ಗಳನ್ನು (`
const pair = createPair<number, string>(1, "hello"); //Explicit type arguments
3. ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳನ್ನು ಮರುರಚಿಸುವುದು (Refactoring Generic Types)
ಕೆಲವೊಮ್ಮೆ, ನಿಮ್ಮ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳ ರಚನೆಯೇ ತೀರ್ಮಾನವನ್ನು ಕಷ್ಟಕರವಾಗಿಸಬಹುದು. ನಿಮ್ಮ ಟೈಪ್ಗಳನ್ನು ಸರಳ ಅಥವಾ ಹೆಚ್ಚು ಸ್ಪಷ್ಟವಾಗಿ ಮಾಡಲು ಮರುರಚಿಸುವುದು ತೀರ್ಮಾನವನ್ನು ಸುಧಾರಿಸಬಹುದು.
//Original, difficult-to-infer type
type ComplexType<A, B, C> = {
a: A;
b: (a: A) => B;
c: (b: B) => C;
};
//Refactored, easier-to-infer type
interface AType {value: string};
interface BType {data: number};
interface CType {success: boolean};
type SimplerType = {
a: AType;
b: (a: AType) => BType;
c: (b: BType) => CType;
};
4. ಟೈಪ್ ಅಸರ್ಷನ್ಗಳನ್ನು ಬಳಸುವುದು (Using Type Assertions)
ಟೈಪ್ ಅಸರ್ಷನ್ಗಳು ಒಂದು ಎಕ್ಸ್ಪ್ರೆಶನ್ನ ಟೈಪ್ ಬಗ್ಗೆ ಕಂಪೈಲರ್ಗಿಂತ ನಿಮಗೆ ಹೆಚ್ಚು ತಿಳಿದಿದೆ ಎಂದು ಹೇಳಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ. ಇವುಗಳನ್ನು ಎಚ್ಚರಿಕೆಯಿಂದ ಬಳಸಿ, ಏಕೆಂದರೆ ತಪ್ಪಾಗಿ ಬಳಸಿದರೆ ದೋಷಗಳನ್ನು ಮರೆಮಾಡಬಹುದು. ಆದಾಗ್ಯೂ, ನೀವು ಟೈಪ್ ಬಗ್ಗೆ ವಿಶ್ವಾಸ ಹೊಂದಿರುವ ಮತ್ತು ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಅದನ್ನು ತೀರ್ಮಾನಿಸಲು ಸಾಧ್ಯವಾಗದ ಸಂದರ್ಭಗಳಲ್ಲಿ ಅವು ಉಪಯುಕ್ತವಾಗಿವೆ.
const value: any = getValueFromSomewhere(); //Assume getValueFromSomewhere returns any
const numberValue = value as number; //Type assertion
console.log(numberValue.toFixed(2)); //Now the compiler treats value as a number
5. ಯುಟಿಲಿಟಿ ಟೈಪ್ಗಳನ್ನು ಬಳಸುವುದು (Utilizing Utility Types)
ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಟೈಪ್ ಮ್ಯಾನಿಪ್ಯುಲೇಷನ್ ಮತ್ತು ತೀರ್ಮಾನಕ್ಕೆ ಸಹಾಯ ಮಾಡುವ ಹಲವಾರು ಅಂತರ್ನಿರ್ಮಿತ ಯುಟಿಲಿಟಿ ಟೈಪ್ಗಳನ್ನು ಒದಗಿಸುತ್ತದೆ. `Partial`, `Required`, `Readonly`, ಮತ್ತು `Pick` ನಂತಹ ಟೈಪ್ಗಳನ್ನು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಟೈಪ್ಗಳ ಆಧಾರದ ಮೇಲೆ ಹೊಸ ಟೈಪ್ಗಳನ್ನು ರಚಿಸಲು ಬಳಸಬಹುದು, ಇದು ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ ತೀರ್ಮಾನವನ್ನು ಸುಧಾರಿಸುತ್ತದೆ.
interface User {
id: number;
name: string;
email?: string;
}
//Make all properties required
type RequiredUser = Required<User>;
function createUser(user: RequiredUser): void {
console.log(user.id, user.name, user.email);
}
createUser({ id: 1, name: "John", email: "john@example.com" }); //No error
//Example using Pick to select a subset of properties
type NameAndEmail = Pick<User, 'name' | 'email'>;
function displayDetails(details: NameAndEmail){
console.log(details.name, details.email);
}
displayDetails({name: "Alice", email: "test@test.com"});
6. `any` ಗೆ ಪರ್ಯಾಯಗಳನ್ನು ಪರಿಗಣಿಸಿ
`any` ತ್ವರಿತ ಪರಿಹಾರವಾಗಿ ಆಕರ್ಷಕವಾಗಿದ್ದರೂ, ಅದು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ಟೈಪ್ ಚೆಕಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ ಮತ್ತು ರನ್ಟೈಮ್ ದೋಷಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು. ಸಾಧ್ಯವಾದಷ್ಟು `any` ಬಳಸುವುದನ್ನು ತಪ್ಪಿಸಲು ಪ್ರಯತ್ನಿಸಿ. ಬದಲಾಗಿ, `unknown` ನಂತಹ ಪರ್ಯಾಯಗಳನ್ನು ಅನ್ವೇಷಿಸಿ, ಇದು ಮೌಲ್ಯವನ್ನು ಬಳಸುವ ಮೊದಲು ಟೈಪ್ ಚೆಕ್ಗಳನ್ನು ಮಾಡಲು ನಿಮ್ಮನ್ನು ಒತ್ತಾಯಿಸುತ್ತದೆ, ಅಥವಾ ಹೆಚ್ಚು ನಿರ್ದಿಷ್ಟವಾದ ಟೈಪ್ ವಿವರಣೆಗಳನ್ನು ಬಳಸಿ.
let unknownValue: unknown = getValueFromSomewhere();
if (typeof unknownValue === 'number') {
console.log(unknownValue.toFixed(2)); //Type check before using
}
7. ಟೈಪ್ ಗಾರ್ಡ್ಗಳನ್ನು ಬಳಸುವುದು (Using Type Guards)
ಟೈಪ್ ಗಾರ್ಡ್ಗಳು ಒಂದು ನಿರ್ದಿಷ್ಟ ಸ್ಕೋಪ್ನಲ್ಲಿ ವೇರಿಯಬಲ್ನ ಟೈಪ್ ಅನ್ನು ಸಂಕುಚಿತಗೊಳಿಸುವ ಫಂಕ್ಷನ್ಗಳಾಗಿವೆ. ಯೂನಿಯನ್ ಟೈಪ್ಗಳೊಂದಿಗೆ ವ್ಯವಹರಿಸುವಾಗ ಅಥವಾ ನೀವು ರನ್ಟೈಮ್ ಟೈಪ್ ಚೆಕಿಂಗ್ ಮಾಡಬೇಕಾದಾಗ ಅವು ವಿಶೇಷವಾಗಿ ಉಪಯುಕ್ತವಾಗಿವೆ. ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಟೈಪ್ ಗಾರ್ಡ್ಗಳನ್ನು ಗುರುತಿಸುತ್ತದೆ ಮತ್ತು ಗಾರ್ಡ್ ಮಾಡಲಾದ ಸ್ಕೋಪ್ನಲ್ಲಿ ವೇರಿಯಬಲ್ಗಳ ಟೈಪ್ಗಳನ್ನು ಪರಿಷ್ಕರಿಸಲು ಅವುಗಳನ್ನು ಬಳಸುತ್ತದೆ.
type StringOrNumber = string | number;
function processValueWithTypeGuard(value: StringOrNumber): void {
if (typeof value === 'string') {
console.log(value.toUpperCase()); //TypeScript knows value is a string here
} else {
console.log(value.toFixed(2)); //TypeScript knows value is a number here
}
}
ಭಾಗಶಃ ತೀರ್ಮಾನದ ಸಮಸ್ಯೆಗಳನ್ನು ತಪ್ಪಿಸಲು ಉತ್ತಮ ಅಭ್ಯಾಸಗಳು
ಭಾಗಶಃ ತೀರ್ಮಾನದ ಸಮಸ್ಯೆಗಳನ್ನು ಎದುರಿಸುವ ಅಪಾಯವನ್ನು ಕಡಿಮೆ ಮಾಡಲು ಅನುಸರಿಸಬೇಕಾದ ಕೆಲವು ಸಾಮಾನ್ಯ ಉತ್ತಮ ಅಭ್ಯಾಸಗಳು ಇಲ್ಲಿವೆ:
- ನಿಮ್ಮ ಟೈಪ್ಗಳೊಂದಿಗೆ ಸ್ಪಷ್ಟವಾಗಿರಿ: ವಿಶೇಷವಾಗಿ ಸಂಕೀರ್ಣ ಸನ್ನಿವೇಶಗಳಲ್ಲಿ, ಕೇವಲ ತೀರ್ಮಾನದ ಮೇಲೆ ಅವಲಂಬಿತರಾಗಬೇಡಿ. ಸ್ಪಷ್ಟವಾದ ಟೈಪ್ ವಿವರಣೆಗಳನ್ನು ಒದಗಿಸುವುದು ಕಂಪೈಲರ್ಗೆ ನಿಮ್ಮ ಉದ್ದೇಶಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಮತ್ತು ಅನಿರೀಕ್ಷಿತ ಟೈಪ್ ದೋಷಗಳನ್ನು ತಡೆಯಲು ಸಹಾಯ ಮಾಡುತ್ತದೆ.
- ನಿಮ್ಮ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳನ್ನು ಸರಳವಾಗಿಡಿ: ಆಳವಾಗಿ ನೆಸ್ಟೆಡ್ ಅಥವಾ ಅತಿಯಾದ ಸಂಕೀರ್ಣ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳನ್ನು ತಪ್ಪಿಸಿ, ಏಕೆಂದರೆ ಅವು ತೀರ್ಮಾನವನ್ನು ಹೆಚ್ಚು ಕಷ್ಟಕರವಾಗಿಸಬಹುದು. ಸಂಕೀರ್ಣ ಟೈಪ್ಗಳನ್ನು ಸಣ್ಣ, ಹೆಚ್ಚು ನಿರ್ವಹಿಸಬಲ್ಲ ತುಣುಕುಗಳಾಗಿ ವಿಭಜಿಸಿ.
- ನಿಮ್ಮ ಕೋಡ್ ಅನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಪರೀಕ್ಷಿಸಿ: ನಿಮ್ಮ ಕೋಡ್ ವಿವಿಧ ಟೈಪ್ಗಳೊಂದಿಗೆ ನಿರೀಕ್ಷೆಯಂತೆ ವರ್ತಿಸುತ್ತದೆಯೇ ಎಂದು ಪರಿಶೀಲಿಸಲು ಯುನಿಟ್ ಪರೀಕ್ಷೆಗಳನ್ನು ಬರೆಯಿರಿ. ತೀರ್ಮಾನವು ಸಮಸ್ಯಾತ್ಮಕವಾಗಿರಬಹುದಾದ ಎಡ್ಜ್ ಕೇಸ್ಗಳು ಮತ್ತು ಸನ್ನಿವೇಶಗಳಿಗೆ ವಿಶೇಷ ಗಮನ ಕೊಡಿ.
- ಕಟ್ಟುನಿಟ್ಟಾದ ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಕಾನ್ಫಿಗರೇಶನ್ ಬಳಸಿ: ನಿಮ್ಮ `tsconfig.json` ಫೈಲ್ನಲ್ಲಿ `strictNullChecks`, `noImplicitAny`, ಮತ್ತು `strictFunctionTypes` ನಂತಹ ಕಟ್ಟುನಿಟ್ಟಾದ ಮೋಡ್ ಆಯ್ಕೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ. ಈ ಆಯ್ಕೆಗಳು ಸಂಭಾವ್ಯ ಟೈಪ್ ದೋಷಗಳನ್ನು ಮೊದಲೇ ಹಿಡಿಯಲು ನಿಮಗೆ ಸಹಾಯ ಮಾಡುತ್ತವೆ.
- ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ತೀರ್ಮಾನ ನಿಯಮಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಿ: ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ತೀರ್ಮಾನ ಅಲ್ಗಾರಿದಮ್ ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದರ ಬಗ್ಗೆ ಪರಿಚಿತರಾಗಿ. ಇದು ಸಂಭಾವ್ಯ ತೀರ್ಮಾನದ ಸಮಸ್ಯೆಗಳನ್ನು ನಿರೀಕ್ಷಿಸಲು ಮತ್ತು ಕಂಪೈಲರ್ಗೆ ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಸುಲಭವಾದ ಕೋಡ್ ಬರೆಯಲು ನಿಮಗೆ ಸಹಾಯ ಮಾಡುತ್ತದೆ.
- ಸ್ಪಷ್ಟತೆಗಾಗಿ ಮರುರಚಿಸಿ: ನೀವು ಟೈಪ್ ತೀರ್ಮಾನದೊಂದಿಗೆ ಹೋರಾಡುತ್ತಿದ್ದರೆ, ಟೈಪ್ಗಳನ್ನು ಹೆಚ್ಚು ಸ್ಪಷ್ಟಪಡಿಸಲು ನಿಮ್ಮ ಕೋಡ್ ಅನ್ನು ಮರುರಚಿಸುವುದನ್ನು ಪರಿಗಣಿಸಿ. ಕೆಲವೊಮ್ಮೆ, ನಿಮ್ಮ ಕೋಡ್ನ ರಚನೆಯಲ್ಲಿ ಒಂದು ಸಣ್ಣ ಬದಲಾವಣೆಯು ಟೈಪ್ ತೀರ್ಮಾನವನ್ನು ಗಮನಾರ್ಹವಾಗಿ ಸುಧಾರಿಸಬಹುದು.
ತೀರ್ಮಾನ
ಭಾಗಶಃ ಟೈಪ್ ತೀರ್ಮಾನವು ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ಟೈಪ್ ಸಿಸ್ಟಮ್ನ ಸೂಕ್ಷ್ಮ ಆದರೆ ಪ್ರಮುಖ ಅಂಶವಾಗಿದೆ. ಇದು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಮತ್ತು ಅದು ಸಂಭವಿಸಬಹುದಾದ ಸನ್ನಿವೇಶಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವ ಮೂಲಕ, ನೀವು ಹೆಚ್ಚು ದೃಢವಾದ ಮತ್ತು ನಿರ್ವಹಿಸಬಲ್ಲ ಕೋಡ್ ಅನ್ನು ಬರೆಯಬಹುದು. ಸ್ಪಷ್ಟ ಟೈಪ್ ವಿವರಣೆಗಳು, ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳ ಮರುರಚನೆ, ಮತ್ತು ಟೈಪ್ ಗಾರ್ಡ್ಗಳಂತಹ ತಂತ್ರಗಳನ್ನು ಬಳಸುವ ಮೂಲಕ, ನೀವು ಅಪೂರ್ಣ ಟೈಪ್ ರೆಸಲ್ಯೂಶನ್ ಅನ್ನು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ನಿಭಾಯಿಸಬಹುದು ಮತ್ತು ನಿಮ್ಮ ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ ಕೋಡ್ ಸಾಧ್ಯವಾದಷ್ಟು ಟೈಪ್-ಸೇಫ್ ಆಗಿದೆಯೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಬಹುದು. ಸಂಕೀರ್ಣ ಜೆನೆರಿಕ್ ಟೈಪ್ಗಳು, ಷರತ್ತುಬದ್ಧ ಟೈಪ್ಗಳು, ಮತ್ತು ಆಬ್ಜೆಕ್ಟ್ ಲಿಟರಲ್ಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವಾಗ ಸಂಭಾವ್ಯ ತೀರ್ಮಾನದ ಸಮಸ್ಯೆಗಳ ಬಗ್ಗೆ ಜಾಗೃತರಾಗಿರಿ. ಟೈಪ್ಸ್ಕ್ರಿಪ್ಟ್ನ ಟೈಪ್ ಸಿಸ್ಟಮ್ನ ಶಕ್ತಿಯನ್ನು ಅಳವಡಿಸಿಕೊಳ್ಳಿ, ಮತ್ತು ವಿಶ್ವಾಸಾರ್ಹ ಮತ್ತು ಸ್ಕೇಲೆಬಲ್ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿರ್ಮಿಸಲು ಅದನ್ನು ಬಳಸಿ.